#include <stdio.h>
#include <errno.h>
#include <string>
#include <cstring>
#include <vector>

#if !defined (_WIN32)
	#include <unistd.h>
#endif


// Include the libircclient & RFC codes files
#include "libircclient.h"
#include "libirc_rfcnumeric.h"

// Include the ActionParser
#include "ActionParser.h"

/*
 * We store data in IRC session context.
 */
typedef struct
{

	char			* inipath;
	char 			* channel;
	char 			* nick;
	char			* pass;
	char 			* server;
	ActionParser	* parser;

} irc_context;

// Handle the event that occurs when the irc connection is established
void event_connect( irc_session_t * session, const char * event, const char * origin, const char ** params, unsigned int count )
{

    std::cout << "Connected \n";

	// Get the saved context for this session
	irc_context * context =( irc_context * )irc_get_ctx( session );
	
	// Use the saved info to join the channel
	irc_cmd_join( session, context->channel, 0 );
	
}

// Handle the event that occurs when numeric messages are sent by the server. Can be found in RFC 1429
void event_numeric( irc_session_t * session, unsigned int event, const char * origin, const char ** params, unsigned int count )
{

	if ( event > 400 )
	{
	
		std::string fulltext;
		for ( unsigned int i = 0; i < count; i++ )
		{
			if ( i > 0 )
				fulltext += " ";

			fulltext += params[i];
		}

		printf( "ERROR %d: %s: %s\n", event, origin ? origin : "?", fulltext.c_str() );
		
	}
	
}

// Handle the event that occurs when a user sends a message to the connected channel (but not your messages)
void event_channel( irc_session_t * session, const char * event, const char * origin, const char ** params, unsigned int count )
{
	
	// Get the saved context
	irc_context * context = ( irc_context * )irc_get_ctx( session );
	ActionParser * parser = context->parser;

	// First, make sure we have an origin and both parameters
	if ( !origin || count != 2 )
		return;
		
	// Define the variables for parsing
	char user[128];
	//const char * channel = params[0];
	const char * message = params[1];
	
	// Get the nickname of the user using the origin
	irc_target_get_nick( origin, user, sizeof( user ) );
	
	// Perform action parsing
	parser->addAction( user, message );
	
	// Perform the action! (SendInput & print to output)
	if( parser->getVoteMode() == VOTE_LEFT )
		parser->performAction();
	
}

int main( int argc, char ** argv )
{

	irc_callbacks_t	callbacks;
	irc_context context;
	unsigned short port = 6667;

	if ( argc != 2 )
	{
	
		printf ("Usage: %s <config.ini path>\n", argv[0]);
		return 1;
		
	}
	
	// Initialize the callbacks (allocated memory & fill with null)
	std::memset( &callbacks, 0, sizeof( callbacks ) );

	// Set up the callbacks we will use
	callbacks.event_connect = event_connect;
	callbacks.event_channel = event_channel;
	callbacks.event_numeric = event_numeric;

	// And create the IRC session; 0 means error
	irc_session_t * session = irc_create_session( &callbacks );
	if( session == 0 )
	{
	
		printf( "Could not create IRC session\n" );
		return 1;
		
	}
	
	context.inipath = argv[1];
	
	// Get the parameters (from ini)
	char iniBuffer[1024];
	
	std::memset( iniBuffer, 0, 1024 );
    GetPrivateProfileString( "server", "server", "", iniBuffer, 1024, context.inipath );
	std::string serverStr = iniBuffer;
	context.server = const_cast< char * >( serverStr.c_str() );
	
	std::memset( iniBuffer, 0, 1024 );
    GetPrivateProfileString( "server", "user", "", iniBuffer, 1024, context.inipath );
	std::string nickStr = iniBuffer;
	context.nick = const_cast< char * >( nickStr.c_str() );
	
	std::memset( iniBuffer, 0, 1024 );
    GetPrivateProfileString( "server", "auth", "", iniBuffer, 1024, context.inipath );
	std::string passStr = iniBuffer;
	context.pass = const_cast< char * >( passStr.c_str() );
	
	std::memset( iniBuffer, 0, 1024 );
    GetPrivateProfileString( "server", "channel", "", iniBuffer, 1024, context.inipath );
	std::string channnelStr = iniBuffer;
	context.channel = const_cast< char * >( channnelStr.c_str() );
	
	// Define the ActionParser (might take these in command-line params later)
	context.parser = new ActionParser( context.inipath );
	
	// Save the context to the session
	irc_set_ctx( session, &context );
	
	// If the port number is specified in the server string, use the port 0 so it gets parsed
	if ( strchr( context.server, ':' ) != 0 )
		port = 0;
		
	//printf( "Server to make: %s, %s, %s, %s \n", context.server, context.nick, context.pass, context.channel );
	
	// Initiate the IRC server connection
	if( irc_connect( session, context.server, port, context.pass, context.nick, 0, 0 ) != 0 )
	{
	
		printf( "Could not connect: %s\n", irc_strerror( irc_errno( session ) ) );
		return 1;
		
	}

	// Run into infinite loop, generating events
	if( irc_run( session ) != 0 )
	{
	
		printf( "Could not connect or I/O error: %s\n", irc_strerror( irc_errno( session ) ) );
		return 1;
		
	}

}
